package com.dynabook.ems.controller;

import cn.hutool.core.util.StrUtil;
import cn.idev.excel.EasyExcel;
import cn.idev.excel.FastExcel;
import cn.idev.excel.read.metadata.ReadSheet;
import cn.idev.excel.support.ExcelTypeEnum;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.dynabook.ems.common.BaseResponse;
import com.dynabook.ems.common.ErrorCode;
import com.dynabook.ems.common.ResultUtils;
import com.dynabook.ems.disruptor.Excel.EmsDisruptorProducer;
import com.dynabook.ems.model.dto.*;
import com.dynabook.ems.model.entity.EmsAbnormal;
import com.dynabook.ems.model.entity.EmsCategory;
import com.dynabook.ems.model.enums.ModelDataTypeEnum;
import com.dynabook.ems.model.listener.EmsCategoryListener;
import com.dynabook.ems.model.listener.EmsDataListener;
import com.dynabook.ems.model.vo.*;
import com.dynabook.ems.model.vo.detailMachine.DetailMachine;
import com.dynabook.ems.service.*;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import io.swagger.annotations.ApiParam;
import lombok.extern.slf4j.Slf4j;
import org.jetbrains.annotations.NotNull;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Lazy;
import org.springframework.util.CollectionUtils;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.validation.Valid;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.nio.file.StandardCopyOption;
import java.util.Arrays;
import java.util.List;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.stream.Collectors;

@RestController
@Slf4j
@Api(tags = "EMS系统接口", description = "设备管理系统相关接口")
public class EmsController {

    @Value("${file.upload-dir}")
    private String UPLOAD_DIR;

    @Resource
    private EmsDisruptorProducer emsDisruptorProducer;

    @Resource
    private EbsSyncService ebsSyncService;

    @Resource
    private EmsMainEngineService emsMainEngineService;


    @Resource
    private EmsAbnormalService emsAbnormalService;




    @Resource
    private EmsMyBorrowService emsMyBorrowService;


    @Resource
    private EmsCategoryService emsCategoryService;
    
    @Resource
    @Lazy
    private EmsProductionRecordsService emsProductionRecordsService;


    @ApiOperation(value = "导出盘点数据接口", notes = "导出研发账册对接表，包含料件基本资料、平均单耗(BOM)、盘点库存三个Sheet")
    @GetMapping("/exportInventoryData")
    public void exportInventoryData(
            @ApiParam(value = "开始日期", required = true, example = "2025-09-01") 
            @RequestParam("startDate") String startDate,
            @ApiParam(value = "结束日期", required = true, example = "2025-10-16") 
            @RequestParam("endDate") String endDate, 
            HttpServletResponse response) {
        emsMainEngineService.exportInventoryData(startDate, endDate, response);
    }
    
    @ApiOperation(value = "分页查询盘点数据API", 
            notes = "提供给外部系统使用的分页查询接口，根据type参数返回对应的数据。" +
                    "type=1返回平均单耗BOM，type=2返回盘点库存。" +
                    "响应data字段直接是分页数据，不包含嵌套的键名")
    @PostMapping("/inventoryData/page")
    public BaseResponse<?> getInventoryDataPage(
            @Valid @RequestBody InventoryDataPageRequest request) {
        log.info("接收到盘点数据分页查询请求: {}", request);
        
        try {
            Object result = emsMainEngineService.getInventoryDataPage(request);
            return ResultUtils.success(result);
        } catch (Exception e) {
            log.error("分页查询盘点数据失败", e);
            return ResultUtils.error(ErrorCode.SYSTEM_ERROR, "分页查询盘点数据失败: " + e.getMessage());
        }
    }
    
    @ApiOperation(value = "查询料件基本资料API", 
            notes = "提供给外部系统使用的按PN料号查询料件基本资料的接口。" +
                    "传入PN料号进行查询，返回该料号的所有料件基本资料。")
    @PostMapping("/materialInfo")
    public BaseResponse<?> getMaterialInfo(
            @Valid @RequestBody MaterialInfoRequest request) {
        log.info("接收到料件基本资料查询请求: {}", request);
        
        try {
            List<InventoryExportVO> result = emsMainEngineService.getMaterialInfo(request);
            return ResultUtils.success(result);
        } catch (Exception e) {
            log.error("查询料件基本资料失败", e);
            return ResultUtils.error(ErrorCode.SYSTEM_ERROR, "查询料件基本资料失败: " + e.getMessage());
        }
    }

    @ApiOperation(value = "根据itemcodeList发送异常邮件")
    @PostMapping("/handleMissingItems")
    public BaseResponse<Boolean> handleMissingItems(@RequestBody @NotNull ItemCodeList itemCodeList) {
        List<ItemCodeVO> missingItemCodes = itemCodeList.getMissingItemCodes();
        if (CollectionUtils.isEmpty(missingItemCodes)) {
            return ResultUtils.error(ErrorCode.PARAMS_ERROR, "请传入itemCodeList");
        }
        boolean result = emsMainEngineService.handleMissingItems(missingItemCodes);
        return ResultUtils.success(result);
    }

    @ApiOperation(value = "根据fixno获取总列表中样机详细信息")
    @PostMapping("/getDetailMachine")
    public BaseResponse<DetailMachine> getDetailMachine(  @RequestBody  MachineFixNODTO machineFixNODTO) {
     String fixedNo = machineFixNODTO.getFixedNo();
     if(StrUtil.isBlank(fixedNo)){
         return ResultUtils.error(ErrorCode.PARAMS_ERROR,"请传入fixedNo");
     }
     DetailMachine detailMachine=emsMainEngineService.getDetailMachine(fixedNo);
     return  ResultUtils.success(detailMachine);
    }
    @ApiOperation(value = "导入型号归类接口", notes = "上传Excel文件并导入数据到系统中，支持.xlsx、.xls和.csv格式")
    @PostMapping("/importItemCode")
    public BaseResponse importItemCode(
            @ApiParam(value = "Excel文件", required = true) @RequestParam("file") MultipartFile file){
        // 判断文件是否为空
        if (file.isEmpty()) {
            return ResultUtils.error(ErrorCode.PARAMS_ERROR, "请上传文件");
        }
        try {
            // 获取文件名
            String filename = file.getOriginalFilename();
            if (filename == null) {
                return ResultUtils.error(ErrorCode.PARAMS_ERROR, "文件名无效");
            }

            // 检查文件扩展名是否为.xlsx或.xls
            if (!filename.toLowerCase().endsWith(".xlsx") && !filename.toLowerCase().endsWith(".xls") && !filename.toLowerCase().endsWith(".csv")) {
                return ResultUtils.error(ErrorCode.PARAMS_ERROR, "请上传Excel文件");
            }

            // 创建文件路径
            Path path = Paths.get(UPLOAD_DIR, filename);
            Path directory = path.getParent();

            // 确保目录存在
            if (!Files.exists(directory)) {
                Files.createDirectories(directory);
            }

            // 检查文件是否存在，如果存在则删除
            if (Files.exists(path)) {
                Files.delete(path);
            }

            // 将文件写入目标目录，使用StandardCopyOption.REPLACE_EXISTING覆盖文件
            Files.copy(file.getInputStream(), path, StandardCopyOption.REPLACE_EXISTING);

            // 读取Excel文件的所有Sheet
            List<ReadSheet> sheets = EasyExcel.read(path.toFile()).build().excelExecutor().sheetList();

            // 创建自定义线程池
            ExecutorService executorService = Executors.newFixedThreadPool(sheets.size());

            // 使用CompletableFuture处理每个Sheet
            List<CompletableFuture<Void>> futures = sheets.stream()
                    .limit(1) // 只处理第一个sheet
                    .map(sheet -> CompletableFuture.runAsync(() -> {
                        try {
                            FastExcel.read(path.toFile(), EmsCategory.class, new EmsCategoryListener(emsCategoryService))
                                    .excelType(detectExcelType(filename))
                                    .sheet(0) // 指定读取第一个sheet（索引为0）
                                    .doRead();
                        } catch (Exception e) {
                            log.error("处理Sheet时发生错误: ", e.getMessage());
                        }
                    }, executorService))
                    .collect(Collectors.toList());

            // 等待所有任务完成
            CompletableFuture.allOf(futures.toArray(new CompletableFuture[0])).join();

            // 关闭线程池
            executorService.shutdown();

            return ResultUtils.success("导入成功");
        } catch (IOException e) {
            log.error("导入失败: ", e.getMessage());
            return ResultUtils.error(ErrorCode.SYSTEM_ERROR, "导入失败");
        }
    }
    @ApiOperation(value = "型号归类列表")
    @PostMapping("/getItemCodeList")
    public BaseResponse<Page<EmsCategory>> getItemCodeList(@RequestBody CategoryListDTO categoryListDTO) {
        Page<EmsCategory> categoryList=emsCategoryService.getEmsCategoryList(categoryListDTO);
        return ResultUtils.success(categoryList);
    }
    @ApiOperation(value = "更新型号归类")
    @PostMapping("/updateItemCode")
    public BaseResponse<Boolean> updateItemCode(@RequestBody EmsCategory emsCategory) {
         Integer id = emsCategory.getId();
         String bigCategory = emsCategory.getBigCategory();
         String category = emsCategory.getCategory();
//        判断每个参数不能为空
        if (id == null  || StrUtil.isBlank(bigCategory)|| StrUtil.isBlank(category)) {
            return ResultUtils.error(ErrorCode.PARAMS_ERROR, "参数不能为空");
        }
        Boolean result =emsCategoryService.updateItemCode(emsCategory);
        return ResultUtils.success(result);
    }
    @ApiOperation(value = "回显型号归类")
    @PostMapping("/getItemCode")
    public BaseResponse<EmsCategory> getItemCode(@RequestBody CategoryIdDTO categoryIdDTO) {
         String id = categoryIdDTO.getId();
//        判断每个参数不能为空
        if (StrUtil.isBlank(id) ) {
            return ResultUtils.error(ErrorCode.PARAMS_ERROR, "参数不能为空");
        }
        EmsCategory result =emsCategoryService.getItemCode(id);
        return ResultUtils.success(result);
    }

    @ApiOperation(value = "导入Excel数据", notes = "上传Excel文件并导入数据到系统中，支持.xlsx、.xls和.csv格式")
    @PostMapping("/importExcel")
    public BaseResponse uploadExcel(
            @ApiParam(value = "Excel文件", required = true) @RequestParam("file") MultipartFile file) {
        // 判断文件是否为空
        if (file.isEmpty()) {
            return ResultUtils.error(ErrorCode.PARAMS_ERROR, "请上传文件");
        }
        try {
            // 获取文件名
            String filename = file.getOriginalFilename();
            if (filename == null) {
                return ResultUtils.error(ErrorCode.PARAMS_ERROR, "文件名无效");
            }

            // 检查文件扩展名是否为.xlsx或.xls
            if (!filename.toLowerCase().endsWith(".xlsx") && !filename.toLowerCase().endsWith(".xls") && !filename.toLowerCase().endsWith(".csv")) {
                return ResultUtils.error(ErrorCode.PARAMS_ERROR, "请上传Excel文件");
            }

            // 创建文件路径
            Path path = Paths.get(UPLOAD_DIR, filename);
            Path directory = path.getParent();

            // 确保目录存在
            if (!Files.exists(directory)) {
                Files.createDirectories(directory);
            }

            // 检查文件是否存在，如果存在则删除
            if (Files.exists(path)) {
                Files.delete(path);
            }

            // 将文件写入目标目录，使用StandardCopyOption.REPLACE_EXISTING覆盖文件
            Files.copy(file.getInputStream(), path, StandardCopyOption.REPLACE_EXISTING);

            // 读取Excel文件的所有Sheet
            List<ReadSheet> sheets = EasyExcel.read(path.toFile()).build().excelExecutor().sheetList();

            // 创建自定义线程池
            ExecutorService executorService = Executors.newFixedThreadPool(sheets.size());

            // 使用CompletableFuture处理每个Sheet
            List<CompletableFuture<Void>> futures = sheets.stream()
                    .map(sheet -> CompletableFuture.runAsync(() -> {
                        try {
                            FastExcel.read(path.toFile(), EmsDataDTO.class, new EmsDataListener(emsDisruptorProducer))
                                    .excelType(detectExcelType(filename))
                                    .sheet()
                                    .doRead();
                        } catch (Exception e) {
                            log.error("处理Sheet时发生错误: ", e.getMessage());
                        }
                    }, executorService))
                    .collect(Collectors.toList());

            // 等待所有任务完成
            CompletableFuture.allOf(futures.toArray(new CompletableFuture[0])).join();

            // 关闭线程池
            executorService.shutdown();

            return ResultUtils.success("导入成功");
        } catch (IOException e) {
            log.error("导入失败: ", e.getMessage());
            return ResultUtils.error(ErrorCode.SYSTEM_ERROR, "导入失败");
        }
    }


    @ApiOperation(value = "同步接口", notes = "触发从EBS系统同步数据的定时任务")
    @PostMapping("/TimingTaskFromEbs")
    public BaseResponse TimingTaskFromEbs() {
        return  ebsSyncService.executeTimingTaskFromEbs();
    }
    @ApiOperation(value = "获取当前使用者列表")
    @PostMapping("/getCurrentUseList")
    public BaseResponse<EmsMyBorrowVO> getCurrentUseList(@RequestBody OnlyFixNODTO onlyFixNODTO) {
            String fixedNo = onlyFixNODTO.getFixedNo();
            if(StrUtil.isBlank(fixedNo)){
                return  ResultUtils.error(ErrorCode.PARAMS_ERROR.getCode(),"样品编号不能为空");
            }
            EmsMyBorrowVO emsMyBorrowVOList = emsMyBorrowService.getCurrentUseList(fixedNo);
            return  ResultUtils.success(emsMyBorrowVOList);
    }
    @ApiOperation(value = "获取样品列表")
    @PostMapping("/getMachineList")
    public BaseResponse<Page<MachineListVO> > getMachineList(@RequestBody MachineListDTO machineListDTO) {
        Page<MachineListVO> page =   emsMainEngineService.getMachineList(machineListDTO);
        return  ResultUtils.success(page);
    }

    @ApiOperation(value = "更新当前使用")
    @PostMapping("/updateUserName")
    public BaseResponse<Boolean> updateUserName() {
        Boolean result =emsMainEngineService.updateUserName();
        return  ResultUtils.success(result);
    }
    @ApiOperation(value = "获取类别列表", notes = "获取所有大类别选项列表")
    @PostMapping("/getCategory")
    public BaseResponse<List<CategoryOptions>> getCategory() {
        List<CategoryOptions> categoryOptionsList = emsCategoryService.getCategory();
        return ResultUtils.success(categoryOptionsList);
    }

    @ApiOperation(value = "获取细分类别列表", notes = "根据大类别获取对应的细分类别选项列表")
    @PostMapping("/getDetailCategory")
    public BaseResponse<List<CategoryOptions>> getDetailCategory(
            @ApiParam(value = "类别信息", required = true) @RequestBody CategoryDTO category) {
        String categoryName = category.getCategory();
        List<CategoryOptions> detailCategoryOptionsList = emsCategoryService.getDetailCategory(categoryName);
        return ResultUtils.success(detailCategoryOptionsList);
    }

    @ApiOperation(value = "获取待入库列表", notes = "分页获取收据列表数据")
    @PostMapping("/getReceiptList")
    public BaseResponse<Page<ReceiptListVO>> getReceiptList(
            @ApiParam(value = "分页和搜索参数", required = true) @RequestBody ReceiptPageDTO receiptPageDTO,
            HttpServletRequest request) {
        // Cookie 处理已经移到切面中自动处理
        Page<ReceiptListVO> page = emsMainEngineService.getReceiptList(receiptPageDTO);
        return ResultUtils.success(page);
    }
    
    @ApiOperation(value = "批量更新机器信息", notes = "根据资产编号列表批量更新设备信息")
    @PostMapping("/updateMachineList")
    public BaseResponse<Boolean> updateMachineList(
            @ApiParam(value = "设备更新信息", required = true) @NotNull @RequestBody UpdateMaicheListDTO updateMaicheListDTO, 
            HttpServletRequest request) {
        UserLoginVO userLogin = (UserLoginVO) request.getSession().getAttribute("user_login");
         log.info("user_login:{}",userLogin);
         String modelName = updateMaicheListDTO.getModelName();
         String category = updateMaicheListDTO.getCategory();
         String bigCategory = updateMaicheListDTO.getBigCategory();
         Integer department = updateMaicheListDTO.getDepartment();
         Integer sectionManager = updateMaicheListDTO.getSectionManager();
        if(StrUtil.isBlank(modelName) || StrUtil.isBlank(category) || StrUtil.isBlank(bigCategory) || department==null || sectionManager== null ){
            return ResultUtils.error(ErrorCode.PARAMS_ERROR,"必填项不能为空");
        }
        Boolean result = emsMainEngineService.updateMachineList(updateMaicheListDTO);
        return ResultUtils.success(result);
    }


    @ApiOperation(value = "入库接口", notes = "根据资产编号列表生成收据")
    @PostMapping("/Receipt")
    public BaseResponse<Boolean> Receipt(
            @ApiParam(value = "资产编号和邮件主题", required = true) @NotNull @RequestBody FixNoDTO fixNoDTO) {
         List<String> fixedNo = fixNoDTO.getFixedNo();
         String subject = fixNoDTO.getSubject();
         if(CollectionUtils.isEmpty(fixedNo) || StrUtil.isBlank(subject)){
            return ResultUtils.error(ErrorCode.PARAMS_ERROR,"fixedNo或者邮件主题必填项不能为空");
        }
        Boolean result = emsMainEngineService.Receipt(fixNoDTO);
         if(!result){
             return  ResultUtils.error(ErrorCode.OPERATION_ERROR,"二次校验不通过");
         }else{
             return ResultUtils.success(result);
         }
    }
    
    @ApiOperation(value = "更新单个机器信息", notes = "根据资产编号更新单个设备的详细信息")
    @PostMapping("/updatetSignleMachine")
    public BaseResponse<Boolean> updatetSignleMachine(
            @ApiParam(value = "设备更新信息", required = true) @NotNull  @RequestBody ReceiptUpdateDTO receiptUpdateDTO,
            HttpServletRequest request) {
         log.info("request:{}",request);
         String modelName = receiptUpdateDTO.getModelName();
         String category = receiptUpdateDTO.getCategory();
         Integer department = receiptUpdateDTO.getDepartment();
         Integer sectionManager = receiptUpdateDTO.getSectionManager();
         String bigCategory = receiptUpdateDTO.getBigCategory();
        String fixedNo = receiptUpdateDTO.getFixedNo();
        if(StrUtil.isBlank(modelName) || StrUtil.isBlank(category) || StrUtil.isBlank(bigCategory) || department==null || sectionManager== null || StrUtil.isBlank(fixedNo)  ){
            return ResultUtils.error(ErrorCode.PARAMS_ERROR,"必填项不能为空");
        }
       Boolean result= emsMainEngineService.updateReceiptData(receiptUpdateDTO);
       return ResultUtils.success(result);
    }

    /**
     * 根据item_code查询样品分类
     * @return
     */
    @ApiOperation(value = "根据item_code查询样品分类", notes = "根据item_code查询样品分类")
    @PostMapping("/getCategoryByItemCode")
    public BaseResponse<CategoryMachine> getCategoryByItemCode(
            @ApiParam(value = "item_code信息", required = true) @RequestBody ItemCodeDTO itemCodeDTO) {
        String itemCode = itemCodeDTO.getItemCode();
        if (itemCode == null) {
            return ResultUtils.error(ErrorCode.PARAMS_ERROR, "请传入item_code");
        }
        CategoryMachine result = emsMainEngineService.getCategoryByItemCode(itemCode);
        return ResultUtils.success(result);
    }
    
    @ApiOperation(value = "获取单个机器信息", notes = "根据资产编号获取单个设备的详细信息")
    @PostMapping("/getSingleMachine")
    public BaseResponse<ReceiptUpdateDTO> getSingleMachine(
            @ApiParam(value = "资产编号信息", required = true) @RequestBody MachineIdDTO machineIdDTO,
            HttpServletRequest request) {
        UserLoginVO userLogin = (UserLoginVO) request.getSession().getAttribute("user_login");
        log.info("user_login:{}",userLogin);
        String fixNO = machineIdDTO.getFixNO();
        if (fixNO == null) {
            return ResultUtils.error(ErrorCode.PARAMS_ERROR, "请传入fixNO");
         }
        ReceiptUpdateDTO result =emsMainEngineService.getSingleMachine(fixNO);
        return ResultUtils.success(result);
    }

    
    @ApiOperation(value = "获取异常列表", notes = "获取系统中所有异常信息列表")
    @PostMapping("/getAbnormalList")
    public BaseResponse<List<EmsAbnormal>> getAbnormalList() {
        List<EmsAbnormal> emsAbnormalList = emsAbnormalService.getAbnormalList();
        return ResultUtils.success(emsAbnormalList);
    }
    @ApiOperation(value = "删除待入库数据")
    @PostMapping("/deleteReceiptData")
    public BaseResponse<Boolean> deleteReceiptData(@Valid @RequestBody DeleteReceiptRequest deleteReceiptRequest) {
        // 参数校验
        if (deleteReceiptRequest == null || CollectionUtils.isEmpty(deleteReceiptRequest.getFixedNos())) {
            return ResultUtils.error(ErrorCode.PARAMS_ERROR, "资产编号列表不能为空");
        }
        
        try {
            Boolean result = emsMainEngineService.deleteReceiptData(deleteReceiptRequest);
            return ResultUtils.success(result);
        } catch (Exception e) {
            log.error("删除待入库数据失败: {}", e.getMessage(), e);
            return ResultUtils.error(ErrorCode.SYSTEM_ERROR, "删除操作失败");
        }
    }

    @ApiOperation(value = "生产记录接口", notes = "根据样机编号列表获取生产记录")
    @PostMapping("/getProductionRecords")
    public BaseResponse<List<ProductionRecordVO>> getProductionRecords(
            @ApiParam(value = "样机编号列表", required = true) @RequestBody ProductionRecordRequest productionRecordRequest) {
        List<ProductionRecordVO> productionRecords = emsProductionRecordsService.getProductionRecords(productionRecordRequest.getFixNo());
        return ResultUtils.success(productionRecords);
    }

    @ApiOperation(value = "待入库数据批量删除", notes = "")
    @PostMapping("/deleteReceiptDataBatch")
    public BaseResponse<Boolean> deleteReceiptDataBatch(@Valid @RequestBody DeleteReceiptRequest deleteReceiptRequest) {
        Boolean result = emsMainEngineService.deleteReceiptDataBatch(deleteReceiptRequest);
        return ResultUtils.success(result);
    }
    @ApiOperation("获取待入库数据类型下拉选项")
    @PostMapping("/getReceiptTypeOptions")
    public BaseResponse<List<CategoryOptions>> getReceiptTypeOptions() {
        log.info("查询待入库数据类型下拉框选项");
        try {
            List<CategoryOptions> options = Arrays.stream(ModelDataTypeEnum.values())
                    .map(status -> {
                        CategoryOptions option = new CategoryOptions();
                        option.setName(status.getText());
                        option.setValue(status.getValue().toString());
                        return option;
                    })
                    .collect(Collectors.toList());

            return ResultUtils.success(options);
        } catch (Exception e) {
            log.error("查询待入库数据类型下拉框选项失败", e);
            return ResultUtils.error(ErrorCode.SYSTEM_ERROR, "查询待入库数据类型下拉框选项失败");
        }
    }
    private ExcelTypeEnum detectExcelType(String filename) {
        if (filename.toLowerCase().endsWith(".xlsx")) {
            return ExcelTypeEnum.XLSX;
        } else if (filename.toLowerCase().endsWith(".xls")) {
            return ExcelTypeEnum.XLS;
        } else if (filename.toLowerCase().endsWith(".csv")) {
            return ExcelTypeEnum.CSV;
        } else {
            throw new IllegalArgumentException("Unsupported file type");
        }
    }
}
